
package uk.ac.manchester.tewpl.iceiface.client.curriculummap;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.google.gwt.user.client.rpc.AsyncCallback;

import uk.ac.manchester.tewpl.iceiface.client.Functors.IterativeLoader;
import uk.ac.manchester.tewpl.iceiface.client.Functors.VoidCallback;
import uk.ac.manchester.tewpl.iceiface.client.model.KBClassModel;
import uk.ac.manchester.tewpl.iceiface.client.model.KBIndividualModel;
import uk.ac.manchester.tewpl.iceiface.client.model.KBObjectPropertyModel;
import uk.ac.manchester.tewpl.iceiface.client.model.KBWorkspaceModel;
import uk.ac.manchester.tewpl.iceiface.client.service.KBServiceAsync;

/*
 * Class to represent a Terminal, instances of which
 * are kept by Airports.
 */
public class Terminal extends Node {
	
	// KnowledgeBase variables
	private KBServiceAsync kbservice = Registry.get("kbservice");
	private KBWorkspaceModel ws = Registry.get("workspace");
	
	// Terminal identifiers
	private KBClassModel terminal;
	private Uri uri;
	private String label;
	private Airport parentAirport;

	// Filter results that match this terminal
	private Collection<FilterResult> filterResults;
	private Collection<String> filterKeywords;
	private boolean filterIsApplied;
	
	/*
	 * Constructor, accepting a KBClassModel
	 */
	public Terminal(KBClassModel t, Airport pAirport) {
		terminal = t;
		label = terminal.getLabel();
		uri = new Uri(terminal.getUri());
		parentAirport = pAirport;
	}
	
	/*
	 * Return the Terminal's Uri
	 */
	public Uri getUri() {
		return uri;
	}
	
	/*
	 * Return the Terminal's label
	 */
	public String getLabel() {
		if (label != null)
			return label;
		else
			return uri.toString();
	}
	
	/*--------------------------------
	 * Filter Methods
	 * -------------------------------*/
	
	/*
	 * Perform search of individuals with filter
	 */
	public void getResultsWithFilter(final String filter, final AsyncCallback<Collection<FilterResult>> cb) {
		kbservice.findIndividualsWithFilter(filter, terminal, ws, new AsyncCallback<Collection<KBIndividualModel>>() {

			@Override
			public void onFailure(Throwable err) {
				cb.onFailure(err);
			}

			@Override
			public void onSuccess(final Collection<KBIndividualModel> individuals) {
				if (individuals.size() > 0) { // If found results
					// Define FilterResults collection
					final Collection<FilterResult> results = new ArrayList<FilterResult>();
					
					// Define indivuals iterator
					final Iterator<KBIndividualModel> iter = individuals.iterator();
					
					// _Define_ iterative loader
					IterativeLoader<KBIndividualModel, VoidCallback> iterLoader =
						new IterativeLoader<KBIndividualModel, VoidCallback>() {
						@Override
						public void load(final KBIndividualModel indiv, final VoidCallback callback) {
							// Retrieve the object property values
							kbservice.findIndividualObjectPropertyValues(indiv.getUri(), ws,
									new AsyncCallback<java.util.Map<KBObjectPropertyModel,Collection<KBIndividualModel>>>() {
								@Override
								public void onFailure(Throwable err) {
									cb.onFailure(err);
								}
		
								@Override
								public void onSuccess(Map<KBObjectPropertyModel,
													  Collection<KBIndividualModel>> objectPropertyValues) {
									results.add(new FilterResult(indiv, objectPropertyValues));
									
									if (iter.hasNext())
										load(iter.next(), callback);
									else
										callback.work();
									}
							});
						}
					};
					
					// _Call_ interative loader, starting at top of iterator
					iterLoader.load(iter.next(), new VoidCallback() {
						@Override
						public void work() { // When all FilterResult created
							// Add filter keyword to list
							if (filterKeywords == null)
								filterKeywords = new ArrayList<String>();
							filterKeywords.add(filter);
							cb.onSuccess(results);
						}
					});
					
				}
				else // If no results found
					cb.onSuccess(null); // Zero results
			}
		});
	}
	
	/*
	 * Adder for single filter result
	 */
	public void addFilterResult(FilterResult result) {
		if (filterResults == null)
			filterResults = new ArrayList<FilterResult>();
		
		filterResults.add(result);
	}
	
	/*
	 * Getter for the filter results
	 */
	public Collection<FilterResult> getFilterResults() {
		return filterResults;
	}
	
	/*
	 * Remover for a filter result
	 */
	@Override
	protected void removeFilterResult(FilterResult result) {
		filterResults.remove(result);
	}

	/*
	 * Clear the filtered results
	 */
	public void clearFilteredResults() {
		filterKeywords = null;
		filterResults = null;
		filterIsApplied = false;
	}

	/*
	 * Return the filter keywords
	 */
	protected Collection<String> getFilterKeywords() {
		return filterKeywords;
	}
	
	/*
	 * Setter for the filter keywords
	 */
	protected void addFilterKeyword(String filter) {
		filterKeywords.add(filter);
	}

	@Override
	protected void setFilterIsApplied() {
		filterIsApplied = true;
	}
	
	@Override
	protected int getCount() {
		if (filterIsApplied) { // If filter is applied _somewhere_
			if (filterResults != null) { // If filter is applied here
				// Return absolute count
				return filterResults.size();
			} else { // If filter is applied _somewhere_, but not here
				return 0;
			}
		} else {
			return terminal.getMemberCount();
		}
	}
	
}
